/*
 *    This file is part of BlobDB.
 *
 *    BlobDB is free software: you can redistribute it and/or modify
 *    it under the terms of the GNU General Public License as published by
 *    the Free Software Foundation, either version 3 of the License, or
 *    (at your option) any later version.
 *
 *    BlobDB is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *    GNU General Public License for more details.
 *
 *    You should have received a copy of the GNU General Public License
 *    along with BlobDB.  If not, see <http://www.gnu.org/licenses/>.
 *    
 *    Copyright(c) 2011 Michael Kankkonen
 *    http://www.vnetcon.org
 */


package org.vnetcon.blobdb.database.backend.gae;

import java.util.ArrayList;
import java.util.List;

import javax.jdo.PersistenceManager;
import javax.jdo.Query;
import javax.jdo.Transaction;

import org.vnetcon.blobdb.database.backend.BaseTableInterface;
import org.vnetcon.blobdb.database.backend.PersistenceManagerInterface;
import org.vnetcon.blobdb.database.backend.QueryInterface;
import org.vnetcon.blobdb.database.backend.QueueEntityInterface;
import org.vnetcon.blobdb.database.backend.TransactionInterface;
import org.vnetcon.blobdb.database.backend.gae.jdo.QueueEntity;
import org.vnetcon.blobdb.database.backend.gae.jdo.Table;
import org.vnetcon.blobdb.database.backend.gae.jdo.TableData;
import org.vnetcon.blobdb.database.backend.gae.jdo.TableID;


public class GAEPersistenceManager implements PersistenceManagerInterface {

	PersistenceManager pm = null;
	QueueEntity qe = null;
	
	public GAEPersistenceManager(PersistenceManager pm){
		this.pm = pm;
	}
	
	
	@Override
	public QueryInterface newQuery(Class<?> clazz) {
		Query q = null;
		GAEQuery gaeq = null;

		if(clazz.getName().indexOf("TableID") > -1){
			q = pm.newQuery(TableID.class);
		}

		if(clazz.getName().indexOf("TableData") > -1){
			q = pm.newQuery(TableData.class);
		}
		
		if(q == null){
			q = pm.newQuery(Table.class);
		}
		gaeq = new GAEQuery(q, clazz);
		return gaeq;
	}

	@Override
	public void makePersistent(Object o) {
		pm.makePersistent(((BaseTableInterface)o).getNativeTable());
	}

	@Override
	public TransactionInterface currentTransaction() {
		Transaction trans = pm.currentTransaction();
		GAETransaction gaetrans = new GAETransaction(trans);
		return gaetrans;
	}

	@Override
	public void close() {
		pm.close();
	}

	@Override
	public void deletePersistentAll(List<?> dels) {
		ArrayList<Object> nativeDels = new ArrayList<Object>();
		int i = 0;
		while(i < dels.size()){
			nativeDels.add(((BaseTableInterface)dels.get(i)).getNativeTable());
			i++;
		}
		pm.deletePersistentAll(nativeDels);
	}

	@Override
	public void deletePersistent(Object o) {
		pm.deletePersistent(((BaseTableInterface)o).getNativeTable());
	}


	@Override
	public void waitForMyTurn(long timestamp, int updateDelay, int tableId, int tableDataId) throws Exception {
		boolean bMyTurn = false;
		qe = new QueueEntity(timestamp, tableId, tableDataId);
		pm.makePersistent(qe);
		// wait for possible other instances updates. According to documentation
		// it is possible to do about 4 updates / second for one entity I guess
		// this mean that this is the time required for PMF to get updated data from BigTable.
		// So this 500 ms should be enough to get latest relevant data from datastore.
		Thread.sleep(updateDelay);
		Query query = pm.newQuery(QueueEntity.class);
		query.setOrdering("creationTime asc");
		query.setRange(0, 1);
		
		while(!bMyTurn){
			List<QueueEntity> res = (List<QueueEntity>)query.execute();
			if(res.size() > 0){
				QueueEntity qeBuf = res.get(0);
				if(qeBuf.getCreationTime() == timestamp){
					bMyTurn = true;
				}
			}
		}
		
	}


	@Override
	public void doneWithUpdate() {
		pm.deletePersistent(qe);
	}

}
